package com.core.jdbc;

import com.core.comment.StringUtil;
import com.core.jdbc.annotate.MyId;
import com.core.jdbc.annotate.MyTable;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SqlUpdateHelper {

    public static <T> Object add(T t) {
        Object id = null;
        try {
            // 编写SQL：
            Map<String, Object> par = new HashMap<>();
            String sql = doSqlParInsert(t, par);
            System.out.println(par);
            System.out.println(sql);
            sql = parseSqlParam(sql, par);
            System.out.println("处理后的sql:" + sql);

            // 执行sql:
            id = SqlHelper.sqlOperate(sql);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return id;
    }

    public static <T> String addToSql(T t) {

        try {
            // 编写SQL：
            Map<String, Object> par = new HashMap<>();
            String sql = doSqlParInsert(t, par);
            System.out.println(par);
            System.out.println(sql);
            sql = parseSqlParam(sql, par);
            System.out.println("处理后的sql:" + sql);
            return sql;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static <T> void addBatch(List<T> tList) throws SQLException {
        List<String> sqls = new LinkedList<>();
        for (T t : tList) {
            sqls.add(addToSql(t));
        }
        SqlHelper.sqlOperateList(sqls);
    }

    public static <T> void update(T t) {
        try {
            // 编写SQL：
            Map<String, Object> par = new HashMap<>();
            String sql = doSqlParUpdate(t, par, false);
            System.out.println(sql);
            sql = parseSqlParam(sql, par);
            System.out.println("处理后的sql:" + sql);

            // 执行sql:
            SqlHelper.sqlOperate(sql);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static <T> void updateSelective(T t) {
        try {
            // 编写SQL：
            Map<String, Object> par = new HashMap<>();
            String sql = doSqlParUpdate(t, par, true);
            System.out.println(sql);
            sql = parseSqlParam(sql, par);
            System.out.println("处理后的sql:" + sql);

            // 执行sql:
            SqlHelper.sqlOperate(sql);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static String parseSqlParam(String sql, Map<String, Object> params) {
        //匹配#{*}格式的占位参数
        String pString = "#\\{.*?\\}";
        //String pString2 = ":[a-zA-Z0-9_$#]*";
        String pString2 = "[^#]?\\{[a-zA-Z0-9_]*}";
        Pattern pattern = Pattern.compile(pString2);
        Matcher matcher = pattern.matcher(sql);

        while (matcher.find()) {
            String paraStr = matcher.group().trim();
            int i = sql.indexOf(paraStr);
            //String paramName = paraStr.replaceAll("#\\{", "").replaceAll("}", "").trim();
            String paramName = paraStr.replaceAll("\\{", "").trim();
            paramName = paramName.replaceAll("}", "");
            if (params != null && i != -1) {
                Object value = params.get(paramName);

                String replace = "''";
                if (value == null) {
                    replace = null + "";
                } else if (value instanceof String) {
                    //校验安全性
                    replace = "'" + value + "'";
                }
                sql = sql.replace("#" + paraStr, replace);

            }

        }
        return sql;
    }


    public static String doSqlParInsert(Object obj, Map<String, Object> par) {
        List<String> names = new ArrayList<>();
        List<String> namesValue = new ArrayList<>();
        try {
            String idName = getIdName(obj.getClass());
            if (StringUtil.isBlack(idName)) {
                throw new MySqlException(obj.getClass().getSimpleName() + "没有主键注解");
            }
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();

                // 过滤class属性
                if (key != null && !"class".equals(key) && !key.equals(idName)) {
                    names.add(key);
                    // namesP.add(":" + key);
                    namesValue.add("#{" + key + "}");
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);
                    par.put(key, value);

                }
            }
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }
        String table = getTableName(obj.getClass());
        if (StringUtil.isBlack(table)) {
            throw new MySqlException(obj.getClass().getSimpleName() + "的表名没有注解");
        }
        String sql = "insert into " + getTableName(obj.getClass()) + " (" + StringUtil.join(names) + ") values (" + StringUtil.join(namesValue) + ")";
        return sql;
    }

    public static String doSqlParUpdate(Object obj, Map<String, Object> par, boolean isSlective) {
        List<String> values = new ArrayList<>();
        //List<String> namesValue = new ArrayList<>();
        Object idValue = null;
        String idName = getIdName(obj.getClass());
        try {

            if (StringUtil.isBlack(idName)) {
                throw new MySqlException(obj.getClass().getSimpleName() + "没有主键注解");
            }
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();

                // 过滤class属性
                if (key != null && !"class".equals(key)) {
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);
                    if (value == null && key.equals(idName)) throw new MySqlException("主键不能为空");
                    if (value == null && !key.equals(idName)) {
                        if (isSlective) continue;
                        values.add(key + "=null");
                    } else {
                        if (value instanceof String) value = "'" + value + "'";
                        if (key.equals(idName)) {
                            idValue = value;
                        } else {
                            values.add(key + "=" + value);
                        }
                    }
                }
            }
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (ReflectiveOperationException e) {
            e.printStackTrace();
        }
        String table = getTableName(obj.getClass());
        if (StringUtil.isBlack(table)) {
            throw new MySqlException(obj.getClass().getSimpleName() + "的表名没有注解");
        }
        String sql = "update " + getTableName(obj.getClass()) + " set " + StringUtil.join(values) + " where " + idName + "=" + idValue + ";";
        return sql;
    }

    public static String getIdName(Class<?> cclazz) {
        Field[] fields = cclazz.getDeclaredFields();
        for (Field field : fields) {
            // Column myid = field.getAnnotation(Column.class);
            MyId myid = field.getAnnotation(MyId.class);
            if (myid != null) {
                return field.getName();
            }
        }
        return null;
    }

    /**
     * 获取主键
     *
     * @param clazz
     * @return
     */
    public static String getTableName(Class<?> clazz) {
        //Table myTable = clazz.getAnnotation(Table.class);
        MyTable myTable = clazz.getAnnotation(MyTable.class);
        if (myTable != null) {
            //String name=myTable.name();
            String name = myTable.value();
            return name;
        }
        return null;
    }

    public static void main(String[] args) throws SQLException {

    }
}
